package ssm.ann.config.exception;

import lombok.extern.java.Log;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.validation.BindingResult;
import org.springframework.validation.FieldError;
import org.springframework.web.HttpRequestMethodNotSupportedException;
import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.bind.annotation.RestControllerAdvice;
import org.springframework.web.context.request.WebRequest;
import org.springframework.web.context.request.async.AsyncRequestTimeoutException;
import org.springframework.web.servlet.mvc.method.annotation.ResponseEntityExceptionHandler;

import javax.servlet.http.HttpServletRequest;
import java.util.Arrays;

/**
 * https://blog.csdn.net/f641385712/article/details/102294670
 * 对 springmvc 中的控制器抛出的异常进行处理
 * 在 spring 3.2 中新增 @ControllerAdvice 注解，用于定义 @ExceptionHandler、@InitBinder、@ModelAttribute，并应用到所有 @RequestMapping 中
 * 在 Controller 层统一对异常进行处理
 */
@Log
@RestControllerAdvice
public class GlobalExceptionHandler extends ResponseEntityExceptionHandler {

    // 会在 handleException 之前调用
    // @ModelAttribute(name = "subject")
    // public void subject() {
    //     System.out.println(SecurityUtils.getSubject());
    // }

    /**
     * 定制化处理 MethodArgumentNotValidException：入参验证异常
     */
    @Override
    public ResponseEntity<Object> handleMethodArgumentNotValid(MethodArgumentNotValidException ex, HttpHeaders headers, HttpStatus status, WebRequest request) {
        BindingResult bindingResult = ex.getBindingResult();
        StringBuffer sb = new StringBuffer();
        for (FieldError fieldError : bindingResult.getFieldErrors()) {
            sb.append(fieldError.getDefaultMessage() + "/");
        }

        status = HttpStatus.FORBIDDEN;

        return super.handleExceptionInternal(ex, sb, headers, status, request);
    }

    /**
     * 定制化处理 MethodArgumentNotValidException：入参验证异常
     */
    // @ExceptionHandler(value = MethodArgumentNotValidException.class)
    public Object handleMethodArgumentNotValidException(HttpServletRequest req, MethodArgumentNotValidException e) {
        BindingResult bindingResult = e.getBindingResult();
        StringBuffer sb = new StringBuffer();
        for (FieldError fieldError : bindingResult.getFieldErrors()) {
            sb.append(fieldError.getDefaultMessage() + "/");
        }
        return sb.substring(0, sb.length() - 1);
    }

    /**
     * 定制化处理 HttpRequestMethodNotSupportedException 异常
     */
    @Override
    protected ResponseEntity<Object> handleHttpRequestMethodNotSupported(
            HttpRequestMethodNotSupportedException ex, HttpHeaders headers, HttpStatus status, WebRequest request) {
        log.warning(ex.getMessage());

        String method = ex.getMethod();
        String[] supportedMethods = ex.getSupportedMethods();

        return super.handleExceptionInternal(ex,
                "不支持的请求类型：" + method + "，支持的请求类型：" + Arrays.toString(supportedMethods),
                headers, status, request);
    }

    @Override
    // @ResponseStatus(HttpStatus.NOT_MODIFIED) // 返回 304 状态码，效果同 HttpServletResponse#sendError(int)，但这样更优雅
    protected ResponseEntity<Object> handleAsyncRequestTimeoutException(AsyncRequestTimeoutException ex, HttpHeaders headers,
                                                                        HttpStatus status, WebRequest webRequest) {
        status = HttpStatus.NOT_MODIFIED;
        log.warning("handleAsyncRequestTimeoutException");
        return super.handleAsyncRequestTimeoutException(ex, headers, status, webRequest);
    }

    /**
     * 兜底异常处理
     */
    // @ResponseStatus(HttpStatus.FORBIDDEN)
    // @ExceptionHandler(value = Exception.class)
    public Object defaultErrorHandler(Exception ex) {
        return ex.getMessage();
    }
}
